#pragma once
#include "essential.h"

// ================================================================================================
// A Basic dynamic array
// ================================================================================================
template<typename T> class DynamicArray {

    private:

        T* arr;
        uint length;
        uint cursize;

        // -- grow the array by 2 * length
        void Grow();
    public:

        // -- default constructor
        DynamicArray();

        // -- copy constructor
        DynamicArray(const DynamicArray<T>& dynarr);

        // -- lifetime
        template<uint size> DynamicArray(T (&arr)[size]);

        // -- destructor
        ~DynamicArray();

        // -- public methods
        void Append(const T& value);

        // -- accessor methods
        uint GetSize();
        uint GetSize() const;
        uint GetLength();
        uint GetLength() const;

        // -- operator overloads
        T& operator[](const uint i);
        const T& operator[](const uint i) const;
        DynamicArray<T> operator=(const DynamicArray& dynarr);
};


// ================================================================================================
// Constructors
// ================================================================================================
template<typename T> inline DynamicArray<T>::DynamicArray() 
                                         : length(10), cursize(0), arr(new T[10]) {
}

// ================================================================================================
// Copy constructor
// ================================================================================================
template<typename T> inline DynamicArray<T>::DynamicArray(const DynamicArray<T>& dynarr) {
    length = dynarr.GetLength();
    cursize = dynarr.GetSize();
    arr = new T[length];
    for(uint i = 0; i < dynarr.GetSize(); ++i) 
        arr[i] = dynarr[i];
}

// ================================================================================================
// Destructor
// ================================================================================================
template<typename T> inline DynamicArray<T>::~DynamicArray() {
    if(arr)
        delete [] arr;
    arr = nullptr;
}

// ================================================================================================
// Append value to the end of the array
// ================================================================================================
template<typename T> inline void DynamicArray<T>::Append(const T& value) {
    if(cursize == length) 
        Grow();

    arr[cursize++] = value;
}

// ================================================================================================
// Grow the array
// ================================================================================================
template<typename T> inline void DynamicArray<T>::Grow() {
   T* temp = arr;
   arr = new T[length * 2];
   for(uint i = 0; i < length; ++i) 
       arr[i] = temp[i];

   length *= 2;
   delete [] temp;
}

// ================================================================================================
// Get the size of the array
// ================================================================================================
template<typename T> inline uint DynamicArray<T>::GetSize() {
    return cursize;
}

template<typename T> inline uint DynamicArray<T>::GetSize() const {
    return cursize;
}

// ================================================================================================
// Get the length of the array
// ================================================================================================
template<typename T> inline uint DynamicArray<T>::GetLength() {
    return length;
}

template<typename T> inline uint DynamicArray<T>::GetLength() const {
    return length;
}

// ================================================================================================
// Operator overloads
// ================================================================================================
template<typename T> 
inline T& DynamicArray<T>::operator[](const uint i) {
    return arr[i];
}

template<typename T>
inline const T& DynamicArray<T>::operator[](const uint i) const {
    return arr[i];
}

template<typename T>
inline DynamicArray<T> DynamicArray<T>::operator=(const DynamicArray<T>& dynarr) {
    delete [] arr;
    length = dynarr.GetLength();
    cursize = dynarr.GetSize();
    arr = new T[length];
    for(uint i = 0; i < dynarr.GetSize(); ++i) 
        arr[i] = dynarr[i];

    return *this;    
}
